<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>webApp(PC + 移动端)</title>
    <link rel="stylesheet" href="../css/common.css">
    <link rel="stylesheet" href="../css/html.css">
</head>
<body>
<div class="container">
    <div class="catalogue">
        <div><a href="#map">高德地图</a></div>
        <div><a href="#h5_Storage">H5本地存储</a></div>
        <div><a href="#h5_from">H5表单验证</a></div>
        <div><a href="#h5_canvas">H5 Canvas 绘图基础</a></div>
        <div><a href="#web_app">移动端开发必备基础</a></div>
        <div><a href="#web_dev">小程序开发工具与基础</a></div>

    </div>
    <div class="substance">
        <div class="one">
            <h1 id="map">高德地图 | <a href="https://lbs.amap.com/api/javascript-api-v2/summary" target="_blank">开发者中心</a></h1>
			<pre>
高德地图: &lt;script src="https://webapi.amap.com/maps?v=2.0&key=13d42b02a7a391210ed42af5451554c7&plugin=AMap.CircleEditor">&lt;/script>
百度地图: &lt;script type="text/javascript" src="https://api.map.baidu.com/api?type=webgl&v=1.0&ak=oFUGBTJaSHQKLK2slVnh7tpAdrzkeVT1">&lt;/script>
			</pre>
        </div>
		<div class="one">
            <h1 id="h5_Storage">H5本地存储
                <a href="../demo/h5/h5-localStorage.html" target="_blank">H5存储demo</a>
                <a href="https://wangdoc.com/javascript/bom/indexeddb#%E6%A6%82%E8%BF%B0" target="_blank">IndexedDB 参考资料</a>
            </h1>
            <pre>
浏览器存储方案:
    (1)Cookie 的大小不超过4KB,且每次请求都会发送回服务器(污染请求头,浪费流量),单个域名下的数量限制(50个左右)
    (2)LocalStorage 在2.5MB到10MB之间(各家浏览器不同),而且不提供搜索功能,不能建立自定义的索引;
    (3)IndexedDB 允许储存大量数据,提供查找接口,还能建立索引

(1)本地存储 - Web Storage:只能存储字符串(同步操作的)
    localStorage和sessionStorage: 相同的使用方法;不同的存储时效
    localStorage存储会持久化;sessionStorage存储会在网页会话结束后失效,网页关闭时失效 、刷新没有问题
    localStorage容量一般在2–5Mb左右;sessionStorage 存储容量不一,部分浏览器不设限
    使用 Storage 时的注意点
        1. 存储容量超出限制: 抛出QuotaExceededError异常,存储值时应使用 try catch 避免异常未捕获
        2. 仅能存储字符串
        3. sessionStorage失效机制: 刷新页面并不能使sessionStorage失效;相同URL不同标签页不能共享sessionStorage
    Web Storage 的优化: (1)减少读取item次数; (2)单个item中尽可能多的存储数据
    API
    (1)setItem(key,value) 设置存储内容     getItem(key) 获取存储内容
        对象[key]=value   对象.key=value
    (2)removeItem(key) 删除key            clear() 可以直接把所有的key 都清空
    (3)length  直接可以查看储存的个数
    (4)key方法获取存储内容
<hr/>
(2)本地存储 - IndexedDB(异步操作的)
    IndexedDB 具有以下特点。
        （1）键值对储存,IndexedDB内部采用对象仓库(object store)存放数据;所有类型的数据都可以直接存入,包括JavaScript对象;每一个数据记录都有对应的主键,主键重复则会抛出一个错误
        （2）异步。 IndexedDB 操作时不会锁死浏览器，用户依然可以进行其他操作,LocalStorage 的操作是同步的。异步设计是为了防止大量数据的读写，拖慢网页的表现。
        （3）支持事务。 IndexedDB 支持事务（transaction）
        （4）同源限制 IndexedDB 受到同源限制，每一个数据库对应创建它的域名。网页只能访问自身域名下的数据库，而不能访问跨域的数据库。
        （5）储存空间大 IndexedDB 的储存空间比 LocalStorage 大得多，一般来说不少于 250MB，甚至没有上限。
        （6）支持二进制储存。 IndexedDB 不仅可以储存字符串，还可以储存二进制数据（ArrayBuffer 对象和 Blob 对象）。
<hr/>
    基本概念:
        (1)数据库：IDBDatabase 对象
            数据库是一系列相关数据的容器。每个域名（严格的说,是协议 + 域名 + 端口）都可以新建任意多个数据库。
            IndexedDB 数据库有版本的概念。同一个时刻，只能有一个版本的数据库存在。如果要修改数据库结构（新增或删除表、索引或者主键）,只能通过升级数据库版本完成。
        (2)对象仓库(IDBObjectStore 对象): 每个数据库包含若干个对象仓库（object store）。它类似于关系型数据库的表格。
                对象仓库保存的是数据记录;每条记录类似于关系型数据库的行,但是只有主键和数据体两部分;
                主键用来建立默认的索引,必须是不同的,否则会报错。主键可以自定义; 数据体可以是任意数据类型,不限于对象
        (3)索引(IDBIndex 对象): 为了加速数据的检索，可以在对象仓库里面，为不同的属性建立索引。
        (4)事务(IDBTransaction 对象)： 数据记录的读写和删改，都要通过事务完成。事务对象提供error、abort和complete三个事件，用来监听操作结果。
        (5)操作请求：IDBRequest 对象
        (6)指针： IDBCursor 对象
        (7)主键集合：IDBKeyRange 对象
<hr/>
    实操:
        (1)打开数据库: var request = window.indexedDB.open(databaseName, version); // 返回IDBRequest对象
                databaseName,如果不存在就新建然后打开; version,如果省略:打开已有数据库时默认是当前版本,新建时默认是1; version只能升不能降
                IDBRequest 对象有三种事件:
                    1- request.onerror = function (event) {  console.log('数据库打开报错'); }; //监听数据库打开失败事件,版本号不能降低
                    2- request.onsuccess = function (event) {  let db = request.result;  console.log('数据库打开成功'); };
                        监听数据库创建或打开成功事件;这时,通过request对象的result属性拿到数据库对象
                    3- request.onupgradeneeded = function (event) {  let db = event.target.result; console.log('数据库版本号升级了'); }
                        版本升级时触发的函数;这时通过事件对象的target.result属性,拿到数据库实例
                创建数据库的时候,因为从无到有会先触发 onupgradeneeded 事件
        (2) 在onupgradeneeded事件中,创建表+索引
                request.onupgradeneeded = function (event) {
                    let db = event.target.result;
                    console.log('数据库版本号升级了');
                    let objectStore;  //如果person表不存在,则创建  ==>设置自增主键: {autoIncrement: true}    自定义主键: {keyPath: 字段名}
                    if (!db.objectStoreNames.contains('person')) objectStore = db.createObjectStore('person', { keyPath: 'id' });
                    objectStore.createIndex('nameIndex', 'name', { unique: true }); //给name字段创建唯一索引nameIndex
                }
        (3) 新增数据
                function add() {
                  var request = db.transaction(['person'], 'readwrite')  //新建事务;  readwrite(读写)/readonly(只读)
                    .objectStore('person')  //获取表对象
                    .add({ id: 1, name: '张三', age: 24, email: 'zhangsan@qq.com' }); //向表格写入数据;通过监听对象的success事件和error事件,了解是否写入成功。
                  request.onsuccess = function (event) { console.log('数据写入成功'); };
                  request.onerror = function (event) { console.log('数据写入失败'); };
                }
                add();
        (4) 读取数据(读取数据也是通过事务完成)
                function read() {
                   var table = db.transaction(['person']).objectStore('person');
                   // 1-getKey(key) 判断key是否存在     2-get(key) 获取key对应的数据      3-getAll() 获取所有数据       4-getAllKeys() 获取所有key
                   // 4-clear() 清除所有数据            4-put() 修改数据                 6-delete() 删除数据          7-add(value) 增加数据
                   var request = table.get(1);
                   // 通过监听对象的success事件和error事件,了解是否读取成功
                   request.onerror = function(event) {console.log('事务失败');};
                   request.onsuccess = function( event) {
                      if (request.result) {
                        console.log('Name: ' + request.result.name);
                        console.log('Age: ' + request.result.age);
                        console.log('Email: ' + request.result.email);
                      } else {
                        console.log('未获得数据记录');
                      }
                   };
                }
                read();
        (4) 更新数据
                function update() {
                  var request = db.transaction(['person'], 'readwrite')
                    .objectStore('person')
                    .put({ id: 1, name: '李四', age: 35, email: 'lisi@example.com' });
                  request.onsuccess = function (event) {console.log('数据更新成功');};
                  request.onerror = function (event) {console.log('数据更新失败');}
                }
                update();
        (5) 删除数据
                function remove() {
                  var request = db.transaction(['person'], 'readwrite')
                    .objectStore('person')
                    .delete(1);
                  request.onsuccess = function (event) {console.log('数据删除成功');};
                }
                remove();
        (6) 遍历数据(遍历数据表格的所有记录,要使用指针对象IDBCursor)  使用游标带来的好处: 可以查询指定数据集范围;   拥有逆序遍历能力
            IDBRange: 指定游标范围
                IDBRange.upperBound(x) // All keys ≤ x
                IDBRange.upperBound(x, true) //All keys < x
                IDBRange.lowerBound(y)   //All keys ≥ y
                IDBRange.lowerBound(y, true) //All keys > y
                IDBRange.only(z) //The key = z
                IDBRange.bound(x, y) // All keys ≥ x && ≤ y
                IDBRange.bound(x, y, true, true) //All keys > x && < y
                IDBRange.bound(x, y, true, false) //All keys > x && ≤ y
                IDBRange.bound(x, y, false, true) //All keys ≥ x && < y
            direction(游标的方向): next(顺序查询)/nextUnique(顺序唯一查询)/prev(逆序查询)/prevUnique(逆序唯一查询)

            function readAll() {
                var table = db.transaction('person').objectStore('person');
                let cursor = table.openCursor(null,'prev');//参数1: 主键获取range   参数2:游标的方向,默认是next
                // 监听游标的onsuccess事件
                cursor.onsuccess = function (event) {
                    var cursor = event.target.result;
                    if (cursor) {
                        console.log('Id: ' + cursor.key);
                        console.log('Name: ' + cursor.value.name);
                        console.log('Age: ' + cursor.value.age);
                        console.log('Email: ' + cursor.value.email);
                        cursor.continue();
                    } else {
                        console.log('没有更多数据了！');
                    }
                };
            }
            readAll();

        (7) 使用索引:  索引的意义在于,可以让你搜索任意字段,也就是说从任意字段拿到数据记录。如果不建立索引,默认只能搜索主键（即从主键取值）;索引自动更新; 索引数据自动排序;
                索引和游标结合带来的好处: 索引按值搜索+游标范围遍历;   索引排序+游标按序遍历
                假定新建表格的时候,对name字段建立了索引:  objectStore.createIndex('nameIndex', 'name', { unique: false });
                var transaction = db.transaction(['person'], 'readonly');
                var table = transaction.objectStore('person');
                var index = table.index('nameIndex');
                var request = index.get('李四');
                // 监听数据获取成功事件
                request.onsuccess = function (e) {
                  var result = e.target.result;
                  if (result) {
                    console.log('数据获取成功');
                  } else {
                    console.log('not data');
                  }
                }
<hr/>
(3)IndexedDB和 Web Storage比较:
    IndexedDB优势: 存储类型更加丰富; 可以在Worker中使用;  条件搜索优势明显;  存储容量更大
    IndexedDB劣势: 学习曲线略陡峭;   兼容性问题略严重

    IndexedDB 的兼容性问题:
        1. IOS8 & 9 中 webview 不支持 indexedDB
        2. Firefox 单次存储 Blob 数据超 50Mb 会抛出异常
        3. IE 10 & 11 有部分子功能未实现

    localStorage 和 sessionStorage: 存取次数影响性能; 只能存储字符串类型数据;   注意存储至上限时的异常处理
    indexedDB: 存储容量大;   需要考虑兼容性;    适合处理复杂数据查询
            </pre>
        </div>
        <div class="one">
            <h1 id="h5_from">H5表单验证
            | <a target="_blank" href="../demo/h5/h5-from.html">H5表单验证demo</a>
            </h1>
            <pre class="bj">
HTML5 表单特点:
    (1)HTML5 表单是对目前 Web 表单的全面提升,它在保持了简便易用的特性的同时;增加了许多内置的控件或者控件属性来满足用户的需求,并且同时减少了开发人员的编程
    (2)XHTML 中需要放在 form 之中的诸如 input/button/select/textarea 等标签元素,在 HTML 5中完全可以放在页面任何位置,然后通过新增的form 属性指向元素所属表单的ID值即可关联起来

新的控件类型:
    (1) email 输入类型
            &lt;input type="email" name="email" /&gt;
            此类型要求输入格式正确的 email 地址,否则浏览器是不允许提交的,并会有一个错误信息提示:此类型在Opera中必须指定name值,否则无效果
    (2) url 输入类型
            &lt;input type="url" /&gt;
            要求输入格式正确的 URL 地址,Opera 中会自动在开始处添加http://
    (3) 日期时间相关输入类型
            &lt;input type="date" /&gt;
            &lt;input type="time" /&gt;
            &lt;input type="month" /&gt;
            &lt;input type="week" /&gt;
            这一系列是很酷的一个类型,完全解决了烦琐的 JS 日历控件问题,但目前 MS 只有Opera/Chrome 新版本支持,且展示效果也不一样
    (4) number 输入类型
            &lt;input type="number" /&gt;
            此类型要求输入格式正确的数字
    (5) range 类型
            &lt;input type="range" step="2" min="0" max="10" value="2" /&gt;
            此类型将显示一个可拖动的滑块条,并可通过设定 max/min/step 值限定拖动范围拖动时会反馈给 value 一个值。
    (6) search 输入类型
            &lt;input type="search" /&gt;
            此类型表示输入的将是一个搜索关键字，通过 results=s 可显示一个搜索小图标。
    (7) tel 输入类型
            &lt;input type="tel" /&gt;
            此类型要求输入一个电话号码，但实际上它并没有特殊的验证，与 text 类型没什么区别。
    (8) color 输入类型
            &lt;input type="color" /&gt;
            此类型可让用户通过颜色选择器选择一个颜色值，并反馈到 value 中。

新的表单属性:
    1、placeholder 属性
        &lt;input type="text" placeholder="点击我会清除" /&gt;
        这是一个很实用的属性,免去了用JS去实现点击清除表单初始值,浏览器支持也还不错,MS除了Firefox,其他标准浏览器都能很好的支持.
    2、require/pattern 属性
        &lt;input type="text" name="require" required="" /&gt;
        &lt;input type="text" name="require1" required="required" /&gt;
        &lt;input type="text" name="require2" pattern="^[1-9]\d{5}$" /&gt;
        require属性必填项;并且可以用于 textarea 以及 hidden/image/submit 类型;
        pattern 类型为正则验证,可以完成各种复杂的验证;(这两种类型在 Opera中必须指定name值,否则无效果)
    3、autofocus 属性
        &lt;input type="text" autofocus="true" /&gt;
        默认聚焦属性，可在页面加载时聚焦到一个表单控件，类似于 JS 的 focus()。
    4.list 属性
        &lt;input type="text" list="ilist"&gt;
            &lt;datalist id="ilist"&gt;
                &lt;option label="a" value="a"&gt;&lt;/option&gt;
                &lt;option label="b" value="b"&gt;&lt;/option&gt;
                &lt;option label="c" value="c"&gt;&lt;/option&gt;
            &lt;/datalist&gt;
        &lt;/input&gt;
        该属性需要与datalist属性共用,datalist是对选择框的记忆,而list 属性可以为选择框自定义记忆的内容。
    5.max/min/step 属性：
        &lt;input type="range" max="100" min="1" step="20" /&gt;
        限制值的输入范围,以及步长
    6.autocomplete 属性：
        &lt;input type="text" autocomplete="on" /&gt;
        此属性是为表单提供自动完成功能,如果该属性为打开状态可很好地自动完成,一般来说此属性必须启动浏览器的自动完成功能。
    7.data 属性：
        &lt;select data="http://class.imooc.com/sc/2"&gt;&lt;/select&gt;
        要为一个 select 下拉别表动态的添加非常多的选项,这些选项大多数都是来自数据库;
        比如说国家、省市列表等等。这个事情非常繁琐;HTML5 将支持data属性为select控件外联数据源！
    8、XML Submission 编码格式
        我们一般常见的是 Web Form 的编码格式是 application/x-www-form-urlencoded;开发人员都很清楚这种格式,数据送到服务器端,可以方便的存取;
        HTML5 提供一种新的数据格式:XML Submission,即 application/x-www-form+xml;简单的举例说,服务器端将直接接收到 XML 形式的表单数据。


html5表单中设置了必填，提交表单的时候如何做到不验证？ novalidate或者formnovalidate
html5约束验证 API:
    1、willValidate 属性
    2、validity 属性
                ValidityState
                    badInput: false //用户提供了一个浏览器不能转换的input
                    customError: false //setCustomValidity()
                    patternMismatch: false //pattern
                    rangeOverflow: false //max
                    rangeUnderflow: false //min
                    stepMismatch: false //step
                    tooLong: false  //maxLength
                    tooShort: false //minLength
                    typeMismatch: false //约束验证的HTML元素类型;  不符合某种类型的,例如email、url等
                    valid: false
                    valueMissing: true  //约束验证的HTML required

    3、validationMessage 属性
    4、checkValidity()方法: 如果元素没有满足它的任意约束,返回false 否则返回 true
    5、setCustomValidity() 方法: 设置自定义验证信息,用于即将实施与验证的约束来覆盖预定义的信息

html5自带验证美化: 要做出不一样的表单验证,我们需要了解一些伪类及css选择器
    1、:required和:optional
    2、:in-range和:out-of-range
    3、:valid和:invalid
    4、:read-only和:read-write


            </pre>
        </div>
        <div class="one">
            <h1 id="h5_canvas">H5 Canvas 绘图基础
                <a href="../demo/h5/canvas/canvas-demo.html" target="_blank">demo</a> | <a href="../demo/h5/canvas/手势解锁图案.html" target="_blank">手势解锁图案demo</a>
            </h1>
            <pre>
Canvas是什么？ Canvas就是画布,Canvas元素用于在网页上绘制2D图形和图像
Canvas使用场景有哪些？  • 动画 + • H5游戏 + • 图表
html5Canvas基础——知识概要
    • 使用Canvas画直线、矩形、圆形以及设置它们的样式
    • Canvas中的图形变换、渐变、文字和图片
    • Canvas的像素获取、阴影和曲线绘制以及区域的剪辑
    • Canvas动画、交互和离屏技术

使用Canvas画基本图形:  • Canvas的坐标体系 + • 使用Canvas画直线、矩形、圆形  + • 为图形设置样式
    (1)Canvas坐标体系
        • canvas默认大小：300x150
        • 通过HTML、CSS、JavaScript设置width和height的区别
            – HTML和JavaScript设置的是画布大小
            – CSS设置的是画布缩放后的大小
        • 坐标系原点及方向: 原点在左上角, 向右为x方向,向下为y方向
    (2)画直线、矩形和圆形
        • 画直线： ctx.moveTo(x1, y1)， ctx.lineTo(x2, y2)
        • 画圆形： ctx.arc(x, y, radius, 0, Math.PI*2, true)
        • 画矩形： 可以通过直线来画，也可以直接用 ctx.strokeRect(x1, y1, x2, y2)

beginPath和closePath
    • beginPath和closePath并不是成对出现的
    • beginPath的作用是开始一条新路径
    • closePath的作用是使当前路径闭合

描边与填充样式
    • strokeStyle用来设置画笔样式，也就是直线、曲线、边框的样式
    • fillStyle用来设置画刷的样式，也就是填充样式
    • lineWidth设置线条的粗细
    注意：这里的样式，是指颜色、渐变色等

Canvas中的图形变换: 图形变换都是针对坐标系而言
    √ 平移：ctx.translate(x, y)
    √ 旋转：ctx.rotate(rad)
    √ 缩放：ctx.scale(x, y);


save和restore: 用来保存和恢复上下文的环境ctx,一般成对出现
    √ ctx.save()：保存当前上下文环境；
    √ ctx.restore()：恢复到上一次的上下文环境。

Canvas中的渐变
    • 线性渐变：ctx.createLinearGradient(xStart, yStart, xEnd,yEnd);  // 起点(xStart, yStart)到终点(xEnd, yEnd)之间的颜色呈渐变
    • gradient.addColorStop可以来控制渐变的颜色
    • 渐变可以理解为一种颜色
    • 径向渐变: ctx.createRadialGradient(xStart,yStart,radiusStart,xEnd,yEnd,radiusEnd);
        – (xStart,yStart)是第一个圆的圆心,radiusStart是第一个圆的半径,(xEnd,yEnd)是第二个圆的圆心,radiusEnd是第二个圆的半径
        – 第一个圆到第二个圆之间的颜色呈渐变

Canvas中的文字:
    • 描边文字：ctx.strokeText(text, x, y)
    • 填充文字：ctx.fillText(text, x, y);
    • 设置字体样式：ctx.font                       – 例如ctx.font = "bold 100px sans-serif";
    • 设置水平对齐方式：ctx.textAlign               – left, start，左对齐；center，居中对齐；end,right，右对齐
    • 设置垂直对齐方式：ctx. textBaseline           – top，顶对齐；middle，居中；bottom，底部对齐
    • 计算文本宽度：ctx.measureText(text).width    – 须在设置字体样式之后计算

Canvas图片
    • 绘制图片3种方法
        – ctx.drawImage(image,x,y)，该方法把图片绘制在(x,y)处
        – ctx.drawImage(image,x,y,w,h)，该方法把图片绘制在(x,y)处,并缩放为宽w，高h
        – ctx.drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh),该方法把图片中(sx,sy)处的宽sw,高sh的区域;绘制到(dx,dy)处,并缩放为宽dw,高dh
    • 在Image加载完成之后绘制
        – 例: var img = new Image();  img.src = "logo.png";  img.onload = function () {ctx.drawImage(img, 0, 0, 40, 40, 0, 0, 80, 80);}


Canvas绘制:   • Canvas的图形画刷和像素获取 + • Canvas阴影绘制 + • Canvas剪辑区域 + • Canvas曲线绘制
    (1)Canvas图形画刷
        • ctx.createPattern可以创建一个画刷模式，进而可以设置到fillStyle里，进行画刷的填充
        • 函数原型：ctx.createPattern(image, type)  //type取值: no-repeat(不平铺) / repeat-x(横方向平) / repeat-y(纵方向平铺) / repeat(全方向平铺)
    (2)Canvas像素操作
        • 获取像素：var imageData = ctx.getImageData(x, y, w, h)   – 返回的是一维数组，[r1,g1,b1,a1,r2,g2,b2,a2...]
        • 设置像素：ctx.putImageData(imageData, x, y)              – 把imageData放在(x, y)处
        • 设置像素：ctx.putImageData(imageData, x, y, dirtyX,dirtyY, dirtyW, dirtyH)    – 只显示(dirtyX, dirtyY)处的宽dirtyW，高dirtyH的区域
    (3)Canvas阴影绘制
        • ctx.shadowOffsetX：阴影x方向的偏移距离          • ctx.shadowOffsetY：阴影y方向的偏移距离
        • ctx.shadowColor：阴影的颜色                   • ctx.shadowBlur：阴影的模糊半径
    (4)Canvas剪辑区域:  第一步：设置一个路径   第二步：调用ctx.clip()   第三步：再绘制图形
    (5)Canvas绘制曲线:
        • 弧线: context.arc(x, y, radius, starAngle,endAngle, anticlockwise)  //圆心(x, y),半径radius,从starAngle到endAngle,anticlockwise代表是否逆时针方向
        • 二次样条曲线：context.quadraticCurveTo(qcpx,qcpy,qx,qy)
        • 贝塞尔曲线:  context.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y)

Canvas绘制曲线生成工具: <a href="http://blogs.sitepointstatic.com/examples/tech/canvas-curves/quadratic-curve.html" target="_blank">二次贝塞尔曲线</a> | <a href="http://blogs.sitepointstatic.com/examples/tech/canvas-curves/bezier-curve.html" target="_blank">三次贝塞尔曲线</a>

Canvas动画和离屏技术: • Canvas动画 + • Canvas离屏技术
    (1)Canvas动画:  • ctx.clearRect(x, y, width, height)  // 清除(x,y)点起,宽width,高height的区域，用于重新绘制
    (2)Canvas离屏技术
        离屏技术是什么？ 通过在离屏Canvas中绘制元素,再复制到显示Canvas中,从而大幅提高性能的一种技术。
        什么时候使用离屏技术？
            – 静态场景绘制特别耗资源,动态场景绘制简单;为了不每次更新动态场景的时候,都去绘制静态场景。
            – 一般把静态场景绘制在离屏canvas上,更新动态场景的时候,把静态场景copy过来,而不是重新绘制。

一个Canvas中的图像绘制到另一个Canvas三种方法:
    (1) ctx.drawImage(canvas,x,y)，该方法把canvas绘制在(x,y)处
    (2) ctx.drawImage(canvas,x,y,w,h)，该方法把canvas绘制在(x,y)处，并缩放为宽w，高h
    (3) ctx.drawImage(canvas,sx,sy,sw,sh,dx,dy,dw,dh)，该方法把canvas中(sx,sy)处的宽sw，高sh的区域，绘制到(dx,dy)处，并缩放为宽dw，高dh

            </pre>
        </div>
        <div class="one">
            <h1 id="web_app">移动端开发必备基础</h1>
            <pre>
我们要学什么:
         移动Web开发基础概念
         移动Web开发基础知识
         响应式布局
         移动端屏幕适配
         移动端事件
         移动端调试
         终端检测
         移动端常见问题
         移动端性能优化
移动Web开发基础概念:     像素          视口--viewport
    (1)像素:
         CSS像素/逻辑像素（logical pixel）/设备独立像素（dip：device independent pixel）
         分辨率
         物理像素(physical pixel) / 设备像素(dp:device pixel)
         设备像素比(dpr: device pixel ratio): dpr=设备像素/CSS像素（缩放比是1的情况下） 例如:dpr = 2 表示 1个css像素用 2x2个设备像素来绘制
         标清屏和高清屏
         缩放:  缩放改变的是CSS像素的大小
         PPI/DPI: PPI(pixels per inch)-每英寸的物理像素点   dpi(dots per inch)-每英寸点数
    (2)视口--viewport:
         width = device-width  //设备宽度
         initial-scale=1      //初始规模
         maximum-scale=1, minimum-scale=1, user-scalable=no  //不允许用户扩展
        &lt;meta  name="viewport"  content="width=device-width,initial-scale=1,maximum-scale=1, minimum-scale=1, user-scalable=no"&gt;
         document.documentElement.clientWidth
         document.documentElement.getBoundingClientRect().width
         window.innerWidth
         screen.width  // 不要用，有兼容性问题
         window.devicePixelRatio
移动Web开发基础知识:     box-sizing   图标字体     flex布局    媒体查询      移动端常用单位
    (1)box-sizing:
         content-box
         border-box
    (2)图标字体:   阿里巴巴矢量图标库（https://www.iconfont.cn/）
    (3)flex布局
        flex布局—容器属性:
             flex-direction: row | row-reverse | column | column-reverse;
             flex-wrap: nowrap | wrap | wrap-reverse;
             flex-flow: &lt;flex-direction&gt; || &lt;flex-wrap&gt;
             justify-content: flex-start | flex-end | center | space-between | space-around;
             align-items: flex-start | flex-end | center | baseline | stretch;
             align-content: flex-start | flex-end | center | space-between | space-around | stretch;

        flex布局—项目属性:
             order: &lt;integer&gt;
             flex-grow: &lt;number&gt;; /* default 0 */
             flex-shrink: &lt;number&gt;; /* default 1 */
             flex-basis: &lt;length&gt;; | auto; /* default auto */
             flex: none | [ &lt;flex-grow&gt; || &lt;flex-shrink&gt; || &lt;flex-basis&gt; ]
             align-self: auto | flex-start | flex-end | center | baseline |stretch;
    (4)媒体查询
         媒体类型:         all/print/screen/speech
         逻辑:            与（ and ）、或（,）、非（not）
        媒体特征表达式:     width/orientation/device-pixel-ratio/aspect-ratio
         策略:            移动优先/PC优先
    (5)移动端常用单位:  px         %         em         rem         vw/vh

            </pre>
            <h2>响应式布局</h2>
            <pre>
什么是响应式布局:
            一个网站兼容多种终端
            对不同屏幕尺寸（大小）做出响应，并进行相应布局的一种移动Web开发方式
响应式布局的原理:
            如何响应不同的屏幕尺寸?
            媒体查询
            Extra small     Small       Medium      Large       Extra large
            <576px          >=575px     >=768px     >=992px     >=1200px

什么是栅格系统(需要引入特定css): 响应式布局的一种实现方式;将页面栅格化
        </pre>
            <h2>移动端屏幕适配</h2>
            <table border="1" style="background-color: #8edff3">
                <tr><td></td><td>移动端适配</td><td>响应式布局</td></tr>
                <tr><td>终端</td><td>仅移动端</td><td>PC端和移动端</td></tr>
                <tr><td>常用单位</td><td>宽高：rem / %<br> 字体：px </td><td>宽：%<br>高、字体：px</td></tr>
                <tr><td>宽和高</td><td>宽和高都随着屏幕大小变化<br>等比例</td><td>宽度变化，高度不变<br>非等比例</td></tr>

            </table>
            <pre>
移动端屏幕适配是什么?  使页面在移动端各种大小的屏幕上都能够正常显示的一种移动端开发方案
与响应式布局的关系: 适应各种屏幕尺寸

其他适配方案:  vw/vh  +  固定宽高

简单适配方案:
            docEl.style.fontSize = viewWidth / ratio + 'px'
            viewWidth = docEl.getBoundingClientRect().width ||window.innerWidth
            ratio = 18.75

通用适配方案:
            dpr = window.devicePixelRatio || 1
            scale = 1 / dpr
            content = 'width=device-width, initial-scale=' + scale + ',
                    minimum-scale=' + scale + ', maximum-scale=' + scale + ',
                    user-scalable=no';
        </pre>
            <h2>移动端事件</h2>
            <pre>
移动端事件有哪些:
            (1)触摸事件(touch事件 + pointer事件)
            (2)手势(gesture)事件
            (3)传感器(sensor)事件

touch事件:
    (1)touchstart/touchmove/touchend
    (2)touches/targetTouches/changedTouches
    (3)pageX pageY/clientX clientY
        </pre>
            <h2>移动端调试和终端检测</h2>
            <pre>
有哪些好用的工具: 浏览器 + 远程调试工具Vorlon.JS + 多终端同步工具Browsersync + 真机查看

什么是终端检测? 检测访问网站的终端是PC还是移动设备
为什么要终端检测: 页面跳转 + 加载相应资源

终端检测:
            (1)userAgent
            (2)navigator.userAgent.match(/android|iphone|ipod|ipad/i)
        </pre>
            <h2>移动端常见问题</h2>
            <table border="1" style="background-color: #8edff3">
                <caption>移动端动画</caption>
                <tr><td></td><td></td><td>DOM</td><td>Canvas</td></tr>
                <tr><td rowspan="3">JavaScript</td><td>setInterval</td><td>√ </td><td>√ </td></tr>
                <tr><td>setTimeout</td><td>√ </td><td>√ </td></tr>
                <tr><td>requestAnimationFrame</td><td>√ </td><td>√ </td></tr>
                <tr><td rowspan="2">CSS3</td><td>transition</td><td>√ </td><td>×</td></tr>
                <tr><td>animation</td><td>√ </td><td>×</td></tr>
            </table>
            <pre>
(1)浏览器兼容性
            HTML5: <a target="_blank" href="https://github.com/aFarkas/html5shiv">兼容处理：html5shiv</a>
            JavaScript: 做特性检测，不要做浏览器检测 + 前缀
            CSS3: <a target="_blank" href="https://modernizr.com/">Modernizr</a>
(2)移动端动画
(3)click 300ms延迟
            原因：双击放大
            解决办法: <a target="_blank" href="https://github.com/ftlabs/fastclick">Fast Click</a>
(4)单行和多行文字溢出省略
            flex布局下的单行文字溢出省略
(5)水平居中和垂直居中
            水平居中:
                    text-align: center
                    margin-left: auto; margin-right: auto
                    position+margin-left/translate
                    flex
            垂直居中:
                    line-height
                    position+margin-top/translate
                    flex
        </pre>
            <h2>移动端性能优化</h2>
            <pre>
什么是性能?
    (1)网站的响应速度
            打开页面到实际能够正常使用的时间间隔
            浏览页面以及和页面进行交互的流畅程度

为什么要优化移动端的性能：提升用户体验 + 移动端网络速度慢 + 移动端设备性能低
性能优化策略分类： 网页资源请求与加载类  + 网页渲染类  + JavaScript脚本类

访问网站的过程：
            (1)输入网站域名
            (2)通过DNS解析找到目标服务器
            (3)目标服务器收到请求后执行一系列操作
            (4)将响应数据发送到用户浏览器
            (5)浏览器处理响应数据，完成网页的渲染呈现

HTML中的性能优化: CSS和JavaScript  +  图片  +  其他优化
CSS中的性能优化:  CSS选择器优化  + CSS属性优化 + 其他优化
JavaScript中的性能优化: DOM操作优化  +  事件优化  +  资源按需加载和预加载  +  其他优化
        </pre>
            <h2>zepto.js移动库</h2>
            <pre>
初识zepto:
            zepto可以说是精简版Jquery
            zepto体积非常小
            zepto多用于移动端

zepto使用: 与Jquery一样
            下载zepto.js库 网址：http://www.zeptojs.cn/
            &lt;script src='zepto.js'>&lt;/script>方式导入
            例子：$('div').text('hello world');

jQuery 与 zepto 的区别：
    (1)针对移动端程序，Zepto 有一些基本的触摸事件可以用来做触摸屏交互（tap事件、swipe 事件），Zepto 是不支持 IE 浏览器的
    (2)DOM 操作的区别：添加 id 时 jQuery 不会生效，而 Zepto 会生效；
             示例：
                (function($) {
                    $(function() {
                        var $insert = $('&lt;p>jQuery 插入&lt;/p>', { id: 'jquery' });
                        $insert.appendTo($('body'));
                    });
                })(window.jQuery);

                Zepto(function($) {
                    var $insert = $('&lt;p>Zepto 插入&lt;/p>', { id: 'zepto' });
                    $insert.appendTo($('body'));
                });
    (3)事件触发的区别：使用 jQuery 时 load 事件的处理函数不会执行；使用Zepto 时 load 事件的处理函数会执行
    (4)事件委托的区别：zepto 中，选择器上所有的委托事件都依次放入到一个队列中，而在 jquery 中则委托成独立的多个事件
    (5)width()和 height()的区别：
        a) Zepto 由盒模型(box-sizing)决定，用.width()返回赋值的 width，用.css('width')返回加 border 等的结果；
        b) jQuery 会忽略盒模型，始终返回内容区域的宽/高(不包含 padding、border)。
    (6)offset()的区别：Zepto 返回{top,left,width,height}；
                     jQuery 返回{top,left};
    (7) Zepto 无法获取隐藏元素宽高，而 jQuery 可以
    (8) Zepto 在操作 dom 的 selected 和 checked 属性时尽量使用 prop 方法，在读取属性值的情况下优先于 attr。
    (9) Zepto 相对于 jQuery 来说是有许多选择不支持的，比如：
            (1) 基本伪类选择器：first、:even 、:odd 、:eq(index) 、:gt(index)、:last 、:lt(index)、:header 等。
            (2) 内容伪类：:contains(text) 、:empty、 :has(selector)、 :parent 等。
            (3) 可见性伪类：:hidden 、:visible 等。
            (4) 属性选择器：[attribute!=value] 等。
            (5) 表单伪类： :input、:text、 :password、 :radio、 :checkbox、:submit、 :image、 :reset、 :button、 :file、 :hidden 等。
            (6) 表单对象属性：:selected 等。

        </pre>
            <h2>Swiper快速切换插件</h2>
            <pre>
webApp美团实战

前置知识点:
    (1)安装node.js
    (2)安装http-server  (静态文件托管)
         npm install http-server  -g  //-g全局安装
    npm install -g cnpm --registry=https://registry.npmmirror.com  //使用淘宝镜像

            </pre>
        </div>
        <div class="one">
            <h1 id="web_dev">小程序开发工具与基础</h1>
            <pre>
申请小程序账号（appid） + 下载并安装微信开发者工具

编写第一个小程序页面:
            (1)小程序文件类型与目录结构
            (2)注册小程序页面，View、Image、Text等组件的基本用法
            (3)Flex弹性盒子模型
            (4)移动端分辨率及小程序自适应单位RPX

移动设备的分辨率与rpx:
    从一张设计图的实现说起
    为什么模拟器下 iphone6 的分辨率是375 而 设计图一般给750？
    如何适配不同的机型？
    pt也称为逻辑分辨率
    pt的大小和屏幕尺寸有关系，简单可以理解为长度和视觉单位
    px指物理分辨率，和屏幕尺寸没有关系。点能有大小吗？
    1个pt可以有1个px构成，也可以有2个，还可以有3个甚至更多组成
    Iphone6 下 2个 px才构成一个 pt
    rpx的作用
    如何做不同分辨率设备的自适应？
            以ip6的物理像素750X1334为视觉稿进行设计，而在小程序中使用rpx为单位
            Ip6下 1px = 1rpx = 0.5 pt
            使用rpx,小程序会自动在不同的分辨率下进行转换，而使用px为单位不会
    为什么要用iphone6的物理分辨率来做设计图？
            Ip6下 1px = 1rpx
            Ip6 plus 下 1px= 0.6rpx
    不是所有的单位都适合用rpx

        </pre>
            <table style="background-color: #8edff3" border="1">
                <caption>移动设备的分辨率与rpx</caption>
                <tr><td>设备</td><td>屏幕尺寸</td><td>分辨率(pt)</td><td>Reader</td><td>分辨率(px)</td><td>渲染后</td><td>PPI(DPI)</td></tr>
                <tr><td>Iphone 3GS</td><td>3.5寸</td><td>320 * 480</td><td>@1X</td><td>320 * 480</td><td>空</td><td>163</td></tr>
                <tr><td>Iphone 4/4S</td><td>3.5寸</td><td>320 * 480</td><td>@2X</td><td>640 * 960</td><td>空</td><td>326</td></tr>
                <tr><td>Iphone 5/5S/5C</td><td>4.0寸</td><td>320 * 568</td><td>@2X</td><td>640 * 1136</td><td>空</td><td>326</td></tr>
                <tr><td>Iphone 6/6S</td><td>4.7寸</td><td>375 * 667</td><td>@2X</td><td>750 * 1334</td><td>空</td><td>326</td></tr>
                <tr><td>Iphone 6/6S Plus</td><td>5.5寸</td><td>414 * 736</td><td>@3X</td><td>1242 * 2208</td><td>1080 * 1920</td><td>401</td></tr>
            </table>
            <pre>



            </pre>
        </div>
    </div>
</div>
</body>
</html>